/* refer to http://developer.android.com/training/animation/zoom.html
 * for zoom/resize view by animation
 * */

package nautilus.lab.renderer;

import java.util.List;


import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
import android.support.v4.content.LocalBroadcastManager;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.HorizontalScrollView;
import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;

public class SnappingHScrollView extends HorizontalScrollView{
	
	private static final String tag = "SnappingHScrollView";
	
	private static final int SWIPE_MIN_DISTANCE = 5;
	private static final int SWIPE_THRESHOLD_VELOCITY = 300;
	
	private LinearLayout internalWrapper;
	
	private List<Bitmap> _items;
	private GestureDetector _gestureDetector;
	private int _activeItem = 0;
	private float _preTouchX = 0;
	private LocalBroadcastManager localBroadcastManager;
	
	private Animator _animator;
	private int _animationDuration;
	private int _horizontalPadding = 0;
	private int _verticalPadding = 0;
	private int _horizontalMargin = 0;
	private int _verticalMargin = 0;
	private int _itemWidth = 0;
	private int _itemHeight = 0;
	
	public SnappingHScrollView(Context context){
		super(context);
		initView();
	}
	
	public SnappingHScrollView(Context context, AttributeSet attrSet){
		super(context, attrSet);
		initView();
	}
	
	public SnappingHScrollView(Context context, AttributeSet attrSet, int defStyle){
		super(context, attrSet, defStyle);
		initView();
	}
	
	private void initView(){
		_horizontalPadding = 0;
		_verticalPadding = 0; 
		_itemWidth = 200;
		_itemHeight = 220;
		_animationDuration = getResources().getInteger(android.R.integer.config_shortAnimTime);
	}
	
	/********************** Being tested ***************************************/
	public void addItemToBegin(){
		Bitmap endbm = createLineEndBitmaps(_items);
		View iv = createChildView(endbm);
		_items.add(endbm);
		_activeItem++;
		internalWrapper.addView(iv, 0);
		scrollToItem(_activeItem);
	}
	public void addItemToEnd(){
		Bitmap endbm = createLineEndBitmaps(_items);
		View iv = createChildView(endbm);
		_items.add(endbm);
		internalWrapper.addView(iv);
	}
	
	public void removeItemBegin(){
		_items.remove(0);
		_activeItem--;
		internalWrapper.removeViewAt(0);
		scrollToItem(_activeItem);
	}
	
	public void removeItemEnd(){
		int size = _items.size();
		internalWrapper.removeViewAt(size-1);
		_items.remove(size-1);
	}
	
	public void scrollToItem(int index){
		int width = getMeasuredWidth();
		index = (index==0)?1:( index==_items.size()-1?index-1:index );
		int scrollTo = (index-1)*_itemWidth + (_itemWidth - (width-_itemWidth)/2);
		scrollTo(scrollTo, 0);
	}
	
	public void scrollToActiveItem(){
		int width = getMeasuredWidth();
		_activeItem = (_activeItem==0)?1:( _activeItem==_items.size()-1?_activeItem-1:_activeItem );
		int scrollTo = (_activeItem-1)*_itemWidth + (_itemWidth - (width-_itemWidth)/2);
		scrollTo(scrollTo, 0);
	}
	
	private View createChildView(Bitmap bm){
		ShadowImageView iv = new ShadowImageView(getContext(), bm);
		LayoutParams lp = new LayoutParams(_itemWidth - (_horizontalMargin + _horizontalPadding)*2, _itemHeight - (_verticalMargin + _verticalPadding)*2 );		
		iv.setLayoutParams(lp);
		iv.setScaleType(ScaleType.CENTER_CROP);
		
		LinearLayout normalView = new LinearLayout(getContext());
		normalView.setPadding(_horizontalPadding, _verticalPadding, _horizontalPadding, _verticalPadding);
		LinearLayout.LayoutParams llp = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
		llp.setMargins(_horizontalMargin, _verticalMargin, _horizontalMargin, _verticalMargin);
		normalView.setLayoutParams(llp);		
		normalView.addView(iv);
		
		ShadowImageView enlargedView = new ShadowImageView(getContext(), bm);
		LayoutParams lp1 = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);		
		enlargedView.setLayoutParams(lp1);
		enlargedView.setScaleType(ScaleType.CENTER_CROP);
		enlargedView.setVisibility(GONE);
		
		FrameLayout item_wrapper = new FrameLayout(getContext());				
		FrameLayout.LayoutParams flp = new FrameLayout.LayoutParams(_itemWidth, LayoutParams.MATCH_PARENT);
		llp.setMargins(_horizontalMargin, _verticalMargin, _horizontalMargin, _verticalMargin);
		item_wrapper.setLayoutParams(flp);		
		item_wrapper.addView(normalView);
		item_wrapper.addView(enlargedView);
		
		return item_wrapper;
	}
	
	public void setItemWidth(int itemWidth){
		_itemWidth = itemWidth;
	}
	
	public int getItemWidth(){
		return _itemWidth;
	}
	
	public void setItemHeight(int height){
		_itemHeight = height;
	}
	
	public int getItemHeight(){
		return _itemHeight;
	}
	
	public void setItemSize(int width, int height){
		_itemWidth = width;
		_itemHeight = height;
	}
	
	public void setHPadding(int horizontalPadding){
		_horizontalPadding = horizontalPadding;
	}
	
	public int getHPadding(){
		return _horizontalPadding;
	}
	
	public void setVPadding(int verticalPadding){
		_verticalPadding = verticalPadding;
	}
	
	public int getVPadding(){
		return _verticalPadding;
	}
	
	public void setPadding(int horizontalPadding, int verticalPadding){
		_horizontalPadding = horizontalPadding;
		_verticalPadding = verticalPadding;
	}
	
	public void setHMargin(int horizontalMargin){
		_horizontalMargin = horizontalMargin;
	}
	
	public int getHMargin(){
		return _horizontalMargin;
	}
	
	public void setVMargin(int verticalMargin){
		_verticalMargin = verticalMargin;
	}
	
	public int getVMargin(){
		return _verticalMargin;
	}
	
	public void setMargin(int horizontalMargin, int verticalMargin){
		_horizontalMargin = horizontalMargin;
		_verticalMargin = verticalMargin;
	}
	
	private void zoomView(View startingView, View endingView){
		if(_animator != null)
			_animator.cancel();
		
		//Load the high-resolution(enlarged) image
		
		//Calculate starting and ending bounds for the zoomed-in image
		final Rect startBounds = new Rect();
		final Rect endingBounds = new Rect();
		final Point globalOffset = new Point();
		
		startingView.getGlobalVisibleRect(startBounds);
		endingView.getGlobalVisibleRect(endingBounds, globalOffset);
		startBounds.offset(-globalOffset.x, -globalOffset.y);
		endingBounds.offset(-globalOffset.x, -globalOffset.y);
		
		float startScale;
		if ((float) endingBounds.width() / endingBounds.height()
                > (float) startBounds.width() / startBounds.height()) {
            // Extend start bounds horizontally
            startScale = (float) startBounds.height() / endingBounds.height();
            float startWidth = startScale * endingBounds.width();
            float deltaWidth = (startWidth - startBounds.width()) / 2;
            startBounds.left -= deltaWidth;
            startBounds.right += deltaWidth;
        } else {
            // Extend start bounds vertically
            startScale = (float) startBounds.width() / endingBounds.width();
            float startHeight = startScale * endingBounds.height();
            float deltaHeight = (startHeight - startBounds.height()) / 2;
            startBounds.top -= deltaHeight;
            startBounds.bottom += deltaHeight;
        }
		
		//Hide the starting view and show the ending view
		startingView.setAlpha(0f);
		endingView.setVisibility(VISIBLE);
		
		//set pivot for scaleX, scaleY
		endingView.setPivotX(0f);
		endingView.setPivotY(0f);
		
		//construct and run the paralled animation
		AnimatorSet aset = new AnimatorSet();
		aset.play(ObjectAnimator.ofFloat(endingView, View.X, startBounds.left, endingBounds.left))
		.with(ObjectAnimator.ofFloat(endingView, View.Y, startBounds.top, endingBounds.top))
		.with(ObjectAnimator.ofFloat(endingView, View.SCALE_X, startScale, 1f))
		.with(ObjectAnimator.ofFloat(endingView, View.SCALE_Y, startScale, 1f));
		
		aset.setDuration(_animationDuration);
		aset.setInterpolator(new DecelerateInterpolator());
		aset.addListener(new AnimatorListenerAdapter(){

			@Override
			public void onAnimationEnd(Animator animation) {
				_animator = null;
			}
			
			@Override
            public void onAnimationCancel(Animator animation) {
				_animator = null;
            }
		});
		aset.start();
		_animator = aset;
	}
	/******************************************************************/
	
	/**
	 * @author Dao Anh Vu
	 * @param items List<Bitmap> danh sach hinh anh dua vao view 
	 */
	public void setFeatureItems(List<Bitmap> items){
		View iv;
		internalWrapper = new LinearLayout(getContext());
		internalWrapper.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
		internalWrapper.setOrientation(LinearLayout.HORIZONTAL);
		addView(internalWrapper);
		_items = items;
		localBroadcastManager = LocalBroadcastManager.getInstance(getContext());
		Bitmap endbm = createLineEndBitmaps(items);
		_items.add(0, endbm);
		_items.add(_items.size(), endbm);
		/*ShadowImageView iv = new ShadowImageView(getContext(), endbm);;
		iv.setLayoutParams(new LayoutParams(200, 220));			
		internalWrapper.addView(iv);*/
		for(Bitmap bm: _items){
			iv = createChildView(bm);			
			internalWrapper.addView(iv);
		}/*		
		iv = new ShadowImageView(getContext(), endbm);;
		iv.setLayoutParams(new LayoutParams(200, 220));			
		internalWrapper.addView(iv);*/
		
		this.setOnTouchListener(new OnTouchListener(){
			public boolean onTouch(View v, MotionEvent ev){
				
				if(_gestureDetector.onTouchEvent(ev))
					return true;
				
				if(ev.getAction() == MotionEvent.ACTION_DOWN){
					_preTouchX = ev.getX();
				}
				
				if(ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL){
					int width = v.getMeasuredWidth();
					float absX = getScrollX() + ev.getX();
					_activeItem = ((int)absX) / _itemWidth;
					
					if(ev.getX()< (width-_itemWidth)/2)
						_activeItem++;
					else
						if(ev.getX()> (width+_itemWidth)/2)
							_activeItem--;
					int scrollTo = (_activeItem-1)*_itemWidth + (_itemWidth - (width-_itemWidth)/2);
					smoothScrollTo(scrollTo, 0);
					//send info to Activity
					/*
					Intent intent = new Intent("NAUTILUS_DATA_COMMUNICATION");
					intent.putExtra("ITEM", _activeItem);
					intent.putExtra("FROM", _preTouchX);
					intent.putExtra("TO", ev.getX());
					intent.putExtra("SCROLLTO", scrollTo);
					intent.putExtra("MEASUREDWIDTH", width);
					localBroadcastManager.sendBroadcast(intent);
					*/
					
					return true;
				}
				
				return false;
			}
		});
		_gestureDetector = new GestureDetector(getContext(), new SnappingGestureDetectorListener());
		
		addOnLayoutChangeListener(new OnLayoutChangeListener(){

			@Override
			public void onLayoutChange(View v, int left, int top, int right,
					int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
				
				//if(v.)
				scrollToActiveItem();
			}
			
		});
	}
	
	private Bitmap createLineEndBitmaps(List<Bitmap> items){
		Bitmap bm = null;
		if(items.size() > 0){
			Bitmap sample = items.get(0);
			bm = Bitmap.createBitmap(sample.getWidth(), sample.getHeight(), Bitmap.Config.ARGB_8888);
			Canvas canvas = new Canvas(bm);
			//Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
			//paint.setColor(Color.BLUE);
			canvas.drawColor(Color.BLUE);
		}
		return bm;
	}
	
	protected class SnappingGestureDetectorListener extends SimpleOnGestureListener{
		
		@Override
		public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY){
			boolean result = super.onScroll(e1, e2, distanceX, distanceY);
			
			//scroll from left to right
			if(e1.getX() < e2.getX()){
				
			}else if(e1.getX() < e2.getX()){
				
			}
			
			if(!result){
				Intent intent = new Intent("NAUTILUS_DATA_COMMUNICATION");
				intent.putExtra("ITEM", _activeItem);
				intent.putExtra("FROM", -5);
				intent.putExtra("TO", -5);
				intent.putExtra("SCROLLTO", -5);
				intent.putExtra("MEASUREDWIDTH", -5);
				localBroadcastManager.sendBroadcast(intent);
			}
				
			return result;
		}
		
	}
	
	class ItemView{
		LinearLayout normalView;
		ShadowImageView enlargedView;
		
		public void addTo(View parent){
			
		}
	}
}
